package io.gitee.chearnee.fw.datasecurity.core.handler.desensitization;

import io.gitee.chearnee.fw.datasecurity.core.util.DataSecurityAssertUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import java.util.ServiceLoader;

/**
 * @author cn
 * @version 1.0
 * @description
 * @date 11/10/2022 2:38 PM
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class SDRuleHandlerFactory {
    private static Map<Class<? extends Annotation>, SDRuleHandler<? extends Annotation>> handlerMap = null;

    private static <T extends Annotation> void addSDRuleHandler(final Class<T> cls, SDRuleHandler<T> handler) {
        handlerMap.put(cls, handler);
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    public static <T extends Annotation> SDRuleHandler<T> getSDRuleHandler(final Class<T> cls) {
        SDRuleHandler sdRuleHandler = handlerMap.get(cls);
        if (sdRuleHandler == null) {
            DataSecurityAssertUtil.desensitizationFail("Not Found 【{}】 SDRuleHandler", cls.getName());
        }
        return sdRuleHandler;
    }

    /**
     * 获取所有的handler
     *
     * @return
     */
    public static Map<Class<? extends Annotation>, SDRuleHandler<? extends Annotation>> getHandlerMap() {
        return handlerMap;
    }

    /**
     * 加载默认处理器和提供spi自定义处理器
     */
    public static void initRuleHandler() {
        handlerMap = new HashMap<>();
        SDNumRuleHandler numRuleHandler = new SDNumRuleHandler();
        addSDRuleHandler(numRuleHandler.getAnnotationType(), numRuleHandler);
        SDGeneralRuleHandler generalRuleHandler = new SDGeneralRuleHandler();
        addSDRuleHandler(generalRuleHandler.getAnnotationType(), generalRuleHandler);
        loadSDRuleHandlerSPI();
    }

    @SuppressWarnings("rawtypes")
    private static void loadSDRuleHandlerSPI() {
        ServiceLoader<SDRuleHandler> load = ServiceLoader.load(SDRuleHandler.class);
        for (SDRuleHandler<?> next : load) {
            handlerMap.put(next.getAnnotationType(), next);
        }
    }

    public static void destroy() {
        handlerMap.clear();
        handlerMap = null;
    }
}
